﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HandyControl.Controls;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using MetadataExtractor.Formats.FileType;
using MetadataExtractor.Formats.QuickTime;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;

namespace PhotoManage.ViewModel;
internal partial class MainViewModel : ObservableObject {
    [ObservableProperty]
    private string currentPath = string.Empty;
    [ObservableProperty]
    private string descPath = @"E:\待整理";
    [ObservableProperty]
    private string consoleText = string.Empty;
    [RelayCommand]
    private async Task StartButtonClick() {
        #region TEST Code
        //string[] testStr = { "mmexport1636535450219.mp4",
        //    "20160103_000000_708.mp4" ,
        //"wx_camera_1653143842307.mp4"};
        //foreach (string str in testStr) {
        //    var dt = GetDateTimeFromFileName(str);
        //    Debug.WriteLine(dt);

        //}
        //return;
        #endregion
        var res = await ConfirmFoldersDateTime();
        if (res is not null) {
            foreach (var item in res) {
                ConsoleText += $"文件'{item.Key}'确定的最终日期是：{item.Value}\n";
            };
            await MoveFile(res);
        }
    }
    [RelayCommand]
    private void DescFoldsClick() {
        Microsoft.Win32.SaveFileDialog dialog = new() {
            Title = "选择目标文件存放的目录",
            FileName = "isthere"
        };
        if (dialog.ShowDialog().GetValueOrDefault()) {
            DescPath = Path.GetDirectoryName(dialog.FileName) ?? string.Empty;
        }
        return;
    }
    [RelayCommand]
    private void SelectFoldsClick() {
        //创建一个打开文件的对话框
        Microsoft.Win32.OpenFileDialog dialog = new();
        //调用ShowDialog()方法显示该对话框，该方法的返回值代表用户是否点击了确定按钮
        if (dialog.ShowDialog().GetValueOrDefault()) {
            CurrentPath = Path.GetDirectoryName(dialog.FileName) ?? string.Empty;
        }
        else {
            CurrentPath = string.Empty;

            Growl.Info("操作取消");
            return;
        }
        return;
    }
    private void ShowAllTags(IEnumerable<MetadataExtractor.Directory> tags) {
        foreach (var directory in tags)
            foreach (var tag in directory.Tags) {
                Debug.WriteLine($"{directory.Name} - {tag.Name} = {tag.Description}");
                ConsoleText += $"{directory.Name} - {tag.Name} = {tag.Description}\n";
            }
    }
    private async Task<Dictionary<string, DateTime>> ConfirmFoldersDateTime() {
        if (string.IsNullOrEmpty(CurrentPath))
            // Set a variable to the My Documents path.
            CurrentPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        ConsoleText = string.Empty;
        DirectoryInfo diTop = new(CurrentPath);
        Dictionary<string, DateTime> results = new();
        await Task.Run(() => {
            try {
                foreach (var di in diTop.EnumerateDirectories("*")) {
                    try {
                        foreach (var fi in di.EnumerateFiles("*", SearchOption.AllDirectories)) {
                            if (ConfirmCamreDateTime(fi) is DateTime dt) {
                                if (dt.Year < 2000) {
                                    Debug.WriteLine($"疑似文件时间提取错误：{fi.FullName}==>{dt}");
                                }
                                results.Add(fi.FullName, dt);

                                //ConsoleText += $"文件'{fi.Name}'确定的最终日期是：{dt}\n";
                                //Debug.WriteLine($"文件'{fi.Name}'确定的最终日期是：{dt}");
                            }
                        }
                    }
                    catch (UnauthorizedAccessException unAuthSubDir) {
                        Debug.WriteLine($"unAuthSubDir: {unAuthSubDir.Message}");
                    }
                }
                try {
                    foreach (var fi in diTop.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) {
                        if (ConfirmCamreDateTime(fi) is DateTime dt) {
                            if (dt.Year < 2000) {
                                Debug.WriteLine($"疑似文件时间提取错误：{fi.FullName}==>{dt}");
                            }
                            results.Add(fi.FullName, dt);
                            //ConsoleText += $"文件'{fi.Name}'确定的最终日期是：{dt}\n";
                            //Debug.WriteLine($"文件'{fi.Name}'确定的最终日期是：{dt}");
                        }
                        //ConsoleText += $"文件'{fi.Name}'确定的最终日期是：{GetDateTimeFromFileName(fi)}\n";
                    }
                }
                catch (UnauthorizedAccessException unAuthSubDir) {
                    Debug.WriteLine($"unAuthSubDir: {unAuthSubDir.Message}");
                }
            }
            catch (DirectoryNotFoundException dirNotFound) {
                Debug.WriteLine($"{dirNotFound.Message}");
            }
            catch (UnauthorizedAccessException unAuthDir) {
                Debug.WriteLine($"unAuthDir: {unAuthDir.Message}");
            }
            catch (PathTooLongException longPath) {
                Debug.WriteLine($"{longPath.Message}");
            }
        });
        return results;
    }
    private async Task MoveFile(Dictionary<string, DateTime> fList) {
        Random ro = new();
        foreach (var file in fList) {
            await Task.Run(() => {
                FileInfo fi = new(file.Key);
                var yPath = file.Value.ToString(@$"yyyy");
                //var mPath = file.Value.ToString(@$"yyyyMM");
                var dPath = Path.Combine(DescPath, yPath);
                //var dPath = Path.Combine(DescPath, yPath, mPath);
                if (!System.IO.Directory.Exists(dPath)) {
                    try {
                        System.IO.Directory.CreateDirectory(dPath);
                    }
                    catch (Exception) {
                        Debug.WriteLine("创建目录错误");
                        return;
                    }
                }
                string descFile = string.Empty;
                do {
                    descFile = Path.Combine(dPath,
                       file.Value.ToString(@"yyyyMMdd_HHmmss_") + $"{ro.Next(1, 999):D3}{fi.Extension.ToLower()}");

                } while (File.Exists(descFile));
                try {
                    fi.MoveTo(descFile);
                }
                catch (Exception) {
                    Debug.WriteLine($"移动文件错误:{fi.FullName}");
                }

            });
        }
    }
    private DateTime? ConfirmCamreDateTime(FileInfo fi) {
        DateTime cdt;
        try {
            IEnumerable<MetadataExtractor.Directory> directories =
                ImageMetadataReader.ReadMetadata(fi.FullName);
            cdt = GetExifDateTime(directories)
                ?? (GetDateTimeFromFileName(fi.Name)
                ?? (DateTime.Compare(fi.CreationTime, fi.LastWriteTime) >= 0
                ? fi.LastWriteTime
                : fi.CreationTime));
        }
        catch (ImageProcessingException) {
            return null;
        }
        catch (IOException ex) {
            return null;
        }
        return cdt;
    }
    private DateTime? GetDateTimeFromFileName(string name) {
        // IMG_20230731_172555
        // 20111021_111322_981
        var r = Regex.Match(name, @"[12]\d{7}_\d{6}");
        if (r.Success) {
            //Debug.WriteLine(r.Value);
            if (DateTime.TryParseExact(r.Value, "yyyyMMdd_HHmmss",
                System.Globalization.CultureInfo.InvariantCulture,
                System.Globalization.DateTimeStyles.None,
                out DateTime dt)) {
                return dt;
            }
        }
        // mmexport1687847804457
        var rs = Regex.Match(name, @"1[67]\d{11}");
        if (rs.Success) {
            //Debug.WriteLine(rs.Value);
            if (long.TryParse(rs.Value, out long stp)) {
                return DateTimeOffset.FromUnixTimeMilliseconds(stp).LocalDateTime;
            }
        }
        // IMGwatch75ofbyvbcrggh1657863225
        var rsl = Regex.Match(name, @"1[67]\d{8}");
        if (rsl.Success) {
            //Debug.WriteLine(rsl.Value);
            if (long.TryParse(rsl.Value, out long stp)) {
                return DateTimeOffset.FromUnixTimeSeconds(stp).LocalDateTime;
            }
        }
        return null;
    }
    private DateTime? GetExifDateTime(IEnumerable<MetadataExtractor.Directory> dirs) {
        var mimeType =
            dirs.OfType<FileTypeDirectory>().FirstOrDefault()?.GetString(FileTypeDirectory.TagDetectedFileMimeType);
        if (mimeType is null)
            return null;

        if (mimeType.StartsWith("image")) {
            //var exif = ;
            if (dirs.OfType<ExifIfd0Directory>().FirstOrDefault()?.
                TryGetDateTime(ExifDirectoryBase.TagDateTime, out DateTime dt) ?? false) {
                if (dt.Year > 1970)
                    return dt;
            }
            //var exifSub = ;
            if (dirs.OfType<ExifSubIfdDirectory>().FirstOrDefault()?.
                TryGetDateTime(ExifDirectoryBase.TagDateTimeOriginal, out DateTime dto) ?? false) {
                if (dto.Year > 1970)
                    return dto;
            }
        }
        else if (mimeType.StartsWith("video")) {
            //var movieHead = ;
            if (dirs.OfType<QuickTimeMovieHeaderDirectory>().FirstOrDefault()?.
                TryGetDateTime(QuickTimeMovieHeaderDirectory.TagModified, out DateTime dtm) ?? false) {
                if (dtm.Year > 1970)
                    return dtm;
            }
            if (dirs.OfType<QuickTimeMovieHeaderDirectory>().FirstOrDefault()?.
                TryGetDateTime(QuickTimeMovieHeaderDirectory.TagCreated, out DateTime dt) ?? false) {
                if (dt.Year > 1970)
                    return dt;
            }
            //var trackHead = ;
            if (dirs.OfType<QuickTimeTrackHeaderDirectory>().FirstOrDefault()?.
                TryGetDateTime(QuickTimeTrackHeaderDirectory.TagCreated, out DateTime dtc) ?? false) {
                if (dtc.Year > 1970)
                    return dtc;
            }
        }
        return null;
    }
}
